/*
 * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.xuexiang.templateproject.activity;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationManager;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.viewpager.widget.ViewPager;

import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.xuexiang.templateproject.R;
import com.xuexiang.templateproject.core.BaseActivity;
import com.xuexiang.templateproject.core.BaseFragment;
import com.xuexiang.templateproject.core.BroadCastManager;
import com.xuexiang.templateproject.core.http.Chart;
import com.xuexiang.templateproject.core.http.UUIDmake;
import com.xuexiang.templateproject.databinding.ActivityMainBinding;
import com.xuexiang.templateproject.fragment.news.GridItemFragment;
import com.xuexiang.templateproject.fragment.news.NewsFragment;
import com.xuexiang.templateproject.fragment.other.AboutFragment;
import com.xuexiang.templateproject.fragment.other.SettingsFragment;
import com.xuexiang.templateproject.fragment.profile.ProfileFragment;
import com.xuexiang.templateproject.fragment.trending.TrendingFragment;
import com.xuexiang.templateproject.utils.GlobalVars;
import com.xuexiang.templateproject.utils.Utils;
import com.xuexiang.templateproject.utils.sdkinit.XUpdateInit;
import com.xuexiang.templateproject.widget.GuideTipsDialog;
import com.xuexiang.xaop.annotation.SingleClick;
import com.xuexiang.xhttp2.XHttp;
import com.xuexiang.xhttp2.callback.impl.IProgressResponseCallBack;
import com.xuexiang.xhttp2.subsciber.ProgressLoadingSubscriber;
import com.xuexiang.xui.adapter.FragmentAdapter;
import com.xuexiang.xui.utils.ResUtils;
import com.xuexiang.xui.utils.ThemeUtils;
import com.xuexiang.xui.utils.WidgetUtils;
import com.xuexiang.xui.utils.XToastUtils;
import com.xuexiang.xui.widget.imageview.RadiusImageView;
import com.xuexiang.xutil.XUtil;
import com.xuexiang.xutil.common.ClickUtils;
import com.xuexiang.xutil.common.CollectionUtils;
import com.xuexiang.xutil.display.Colors;
import com.xuexiang.xutil.file.FileUtils;
import com.xuexiang.xutil.tip.ToastUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.UUID;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

/**
 * 程序主页面,只是一个简单的Tab例子
 *
 * @author xuexiang
 * @since 2019-07-07 23:53
 */
public class MainActivity extends BaseActivity<ActivityMainBinding> implements NewsFragment.OnListener, View.OnClickListener, BottomNavigationView.OnNavigationItemSelectedListener, ClickUtils.OnClick2ExitListener, Toolbar.OnMenuItemClickListener, SensorEventListener {
    boolean tag = false;
    private String[] mTitles;
    String filePath;
    File fichero;
    OutputStreamWriter fout;
    String fileName;


    Context context = this;
    SensorManager mSensorManager;
    Sensor Sensor_Acc;
    Sensor Sensor_Gyr;
    Sensor Sensor_Mag;
    Sensor Sensor_Pre;
    Sensor Sensor_Ligh;
    Sensor Sensor_Prox;
    Sensor Sensor_Humi;
    Sensor Sensor_Temp;
    Sensor Sensor_AHRS;
    Sensor Sensor_LACC;
    Sensor Sensor_SGMO;
    Sensor Sensor_STEP;
    Sensor Sensor_GAHRS;
    //TODO:增加处

    boolean primer_sensor_cambia = true;
    long tiempo_inicial_ns_raw = 0;
    long timestamp_ns;
    double timestamp;
    long contador_Acce = 0;
    long contador_Gyro = 0;
    long contador_Magn = 0;
    long contador_Pres = 0;
    long contador_Ligh = 0;
    long contador_Prox = 0;
    long contador_Humi = 0;
    long contador_Temp = 0;
    long contador_Ahrs = 0;
    long contador_Sgmo = 0;
    long contador_Lacc = 0;
    long contador_Step = 0;
    long contador_Gahrs = 0;
    //TODO:增加处
    float freq_medida_Acce = 0;
    float freq_medida_Gyro = 0;
    float freq_medida_Magn = 0;
    float freq_medida_Pres = 0;
    float freq_medida_Ligh = 0;
    float freq_medida_Prox = 0;
    float freq_medida_Humi = 0;
    float freq_medida_Temp = 0;
    float freq_medida_Ahrs = 0;

    double timestamp_Acce_last = 0;
    double timestamp_Gyro_last = 0;
    double timestamp_Magn_last = 0;
    double timestamp_Pres_last = 0;
    double timestamp_Ligh_last = 0;
    double timestamp_Prox_last = 0;
    double timestamp_Humi_last = 0;
    double timestamp_Temp_last = 0;
    double timestamp_Ahrs_last = 0;

    double timestamp_Acce_last_update = 0;
    double timestamp_Gyro_last_update = 0;
    double timestamp_Magn_last_update = 0;
    double timestamp_Pres_last_update = 0;
    double timestamp_Ligh_last_update = 0;
    double timestamp_Prox_last_update = 0;
    double timestamp_Humi_last_update = 0;
    double timestamp_Temp_last_update = 0;
    double timestamp_Ahrs_last_update = 0;
    double timestamp_Gnss_last_update = 0;
    double timestamp_Wifi_last_update = 0;
    double timestamp_Blue_last_update = 0;
    double timestamp_Ble4_last_update = 0;
    double timestamp_Soun_last_update = 0;
    double timestamp_Rfid_last_update = 0;
    double timestamp_Imux_last_update = 0;
    double timestamp_Imul_last_update = 0;
    double timestamp_MIMU22BT_last_update = 0;
    double deltaT_update = 0.25;   // cada 0.25 segundo actualizo la pantalla con las medidas (4Hz)
    private static final int MY_PERMISSION_ACCESS_COARSE_LOCATION = 11;
    private static final int MY_PERMISSION_ACCESS_FINE_LOCATION = 12;
    String URL = GlobalVars.url;//TODO:后端接口修改(两个)
    String urlOpt = URL+"opt";String UUID="";
    String urlFile = "";

    Chart OPTSend = new Chart();
    private LocalReceiver mReceiver;
    String str_fecha_actual;

    class LocalReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {


            String flag2 = intent.getStringExtra("opt");
            Log.e("opt", flag2);
            if (!flag2.equals("stop")) {
                new Thread(() -> {
                    try {
                        try {
                            OPTSend.run(urlOpt, "opt", flag2, "UUID", UUID);
                        } catch (RuntimeException e) {
                            ToastUtils.toast("无法连接到服务器2");
                        }
                    } catch (Exception e) {
                        ToastUtils.toast("请求错误!");
                    }
                });
            } else {
                try {
                    fout.flush();
                    fout.close();
                    tag = false;
                    urlFile =URL+"file";
                    OPTSend.upload(urlFile, filePath, UUID, fileName);


                } catch (IOException e) {
                    ToastUtils.toast("文件传输错误!");
                } catch (Exception e) {
                    ToastUtils.toast("文件传输超时!");
                }
            }
        }
    }

    private void loadData(String orderid) {

    }

    @Override
    protected void onDestroy() {
        BroadCastManager.getInstance().unregisterReceiver(this, mReceiver);//注销广播接收者
        super.onDestroy();
    }


    @Override
    protected ActivityMainBinding viewBindingInflate(LayoutInflater inflater) {
        return ActivityMainBinding.inflate(inflater);
    }

    String a() throws IOException {
        if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
            finish();
        }
        boolean mExternalStorageAvailable = false;
        boolean mExternalStorageWriteable = false;
        String state = Environment.getExternalStorageState();

        if (Environment.MEDIA_MOUNTED.equals(state)) {
            // We can read and write the media
            mExternalStorageAvailable = mExternalStorageWriteable = true;
        } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
            // We can only read the media
            mExternalStorageAvailable = true;
            mExternalStorageWriteable = false;
        } else {
            // Something else is wrong. It may be one of many other states, but all we need
            //  to know is we can neither read nor write
            mExternalStorageAvailable = mExternalStorageWriteable = false;
        }
        long CpuTimeStamp = System.nanoTime(); // in nano seconds
        if (primer_sensor_cambia) {
            tiempo_inicial_ns_raw = CpuTimeStamp;  // en nano segundos
            Log.i("", "Tiempo inicial: " + tiempo_inicial_ns_raw + " ms");
            timestamp_Acce_last_update = 0;
            timestamp_Gyro_last_update = 0;
            timestamp_Magn_last_update = 0;
            timestamp_Pres_last_update = 0;
            timestamp_Prox_last_update = 0;
            timestamp_Ahrs_last_update = 0;
            timestamp_Gnss_last_update = 0;
            timestamp_Wifi_last_update = 0;
            timestamp_Soun_last_update = 0;
            timestamp_Imul_last_update = 0;
            timestamp_Imux_last_update = 0;
        }

        SimpleDateFormat sf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss", Locale.US);  // formato de la fecha
        Date fecha_actual = new Date();
        str_fecha_actual = sf.format(fecha_actual);  // formatear fecha
        File fileEx = this.getExternalFilesDir(null);
        String dir = fileEx.getAbsolutePath() + "/" + "LogFiles_GetSensorData";
        File file2 = new File(dir);
        if (!file2.exists()) {
            file2.mkdirs();
        }
        fileName=UUID+"@"+ str_fecha_actual + ".txt";
        fichero = new File(file2.getAbsolutePath(), UUID+"@"+ str_fecha_actual + ".txt");
        fout = new OutputStreamWriter(Files.newOutputStream(fichero.toPath()));
        tag = true;
        return fichero.toPath().toString();
    }

    @Override
    public void getResult(String data) throws IOException {
        filePath = a();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

        initViews();
        initData();
        initListeners();

        Sensor_Acc = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        Sensor_Gyr = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
        Sensor_Mag = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        Sensor_Pre = mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
        Sensor_Ligh = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
        Sensor_Prox = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
        Sensor_Humi = mSensorManager.getDefaultSensor(Sensor.TYPE_RELATIVE_HUMIDITY);
        Sensor_Temp = mSensorManager.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE);
        Sensor_AHRS = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
        Sensor_LACC = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
        Sensor_SGMO = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
        Sensor_STEP = mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
        Sensor_GAHRS = mSensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR);

        try {
            IntentFilter filter = new IntentFilter();
            filter.addAction("p");
            mReceiver = new LocalReceiver();
            BroadCastManager.getInstance().registerReceiver(this,
                    mReceiver, filter);//注册广播接收者


        } catch (Exception e) {
            ToastUtils.toast(e.toString());
        }
        String sdCardDir = Environment.getExternalStorageDirectory().getAbsolutePath();
        File appDir = new File(sdCardDir, "CaChe");
        if (!appDir.exists()) {
            appDir.mkdir();
        }
        String fileName = "UUID" + ".txt";//这里是进行读取我们保存文件的名称
        File file = new File(appDir, fileName);
        if (!file.exists()) {
            try {
                UUIDmake.saveBitmap();
                UUID = UUIDmake.readKey();
            } catch (IOException e) {
                XToastUtils.toast(e.toString());
            }
        } else {
            try {
                UUID = UUIDmake.readKey();
            } catch (IOException e) {
                XToastUtils.toast(e.toString());
            }
        }

    }


    @Override
    protected boolean isSupportSlideBack() {
        return false;
    }

    private void initViews() {
        WidgetUtils.clearActivityBackground(this);

        mTitles = ResUtils.getStringArray(R.array.home_titles);
        binding.includeMain.toolbar.setTitle(mTitles[0]);
        binding.includeMain.toolbar.inflateMenu(R.menu.menu_main);
        binding.includeMain.toolbar.setOnMenuItemClickListener(this);

        initHeader();

        //主页内容填充
        BaseFragment[] fragments = new BaseFragment[]{
                new NewsFragment(),
                new TrendingFragment(),
                new ProfileFragment()
        };
        FragmentAdapter<BaseFragment> adapter = new FragmentAdapter<>(getSupportFragmentManager(), fragments);
        binding.includeMain.viewPager.setOffscreenPageLimit(mTitles.length - 1);
        binding.includeMain.viewPager.setAdapter(adapter);
    }

    private void initData() {
        GuideTipsDialog.showTips(this);
        XUpdateInit.checkUpdate(this, false);
    }

    private void initHeader() {
        binding.navView.setItemIconTintList(null);
        View headerView = binding.navView.getHeaderView(0);
        LinearLayout navHeader = headerView.findViewById(R.id.nav_header);
        RadiusImageView ivAvatar = headerView.findViewById(R.id.iv_avatar);
        TextView tvAvatar = headerView.findViewById(R.id.tv_avatar);
        TextView tvSign = headerView.findViewById(R.id.tv_sign);

        if (Utils.isColorDark(ThemeUtils.resolveColor(this, R.attr.colorAccent))) {
            tvAvatar.setTextColor(Colors.WHITE);
            tvSign.setTextColor(Colors.WHITE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                ivAvatar.setImageTintList(ResUtils.getColors(R.color.xui_config_color_white));
            }
        } else {
            tvAvatar.setTextColor(ThemeUtils.resolveColor(this, R.attr.xui_config_color_title_text));
            tvSign.setTextColor(ThemeUtils.resolveColor(this, R.attr.xui_config_color_explain_text));
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                ivAvatar.setImageTintList(ResUtils.getColors(R.color.xui_config_color_gray_3));
            }
        }


        ivAvatar.setImageResource(R.drawable.head);
        tvAvatar.setText(R.string.app_name);
        tvSign.setText("这个家伙很懒，什么也没有留下～～");
        navHeader.setOnClickListener(this);
    }

    protected void initListeners() {
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, binding.drawerLayout, binding.includeMain.toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        binding.drawerLayout.addDrawerListener(toggle);
        toggle.syncState();

        //侧边栏点击事件
        binding.navView.setNavigationItemSelectedListener(menuItem -> {
            if (menuItem.isCheckable()) {
                binding.drawerLayout.closeDrawers();
                return handleNavigationItemSelected(menuItem);
            } else {
                int id = menuItem.getItemId();
                if (id == R.id.nav_settings) {
                    openNewPage(SettingsFragment.class);
                } else if (id == R.id.nav_about) {
                    openNewPage(AboutFragment.class);
                } else {
                    XToastUtils.toast("点击了:" + menuItem.getTitle());
                }
            }
            return true;
        });
        //主页事件监听
        binding.includeMain.viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                MenuItem item = binding.includeMain.bottomNavigation.getMenu().getItem(position);
                binding.includeMain.toolbar.setTitle(item.getTitle());
                item.setChecked(true);
                updateSideNavStatus(item);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
        binding.includeMain.bottomNavigation.setOnNavigationItemSelectedListener(this);
    }

    /**
     * 处理侧边栏点击事件
     *
     * @param menuItem
     * @return
     */
    private boolean handleNavigationItemSelected(@NonNull MenuItem menuItem) {
        int index = CollectionUtils.arrayIndexOf(mTitles, menuItem.getTitle());
        if (index != -1) {
            binding.includeMain.toolbar.setTitle(menuItem.getTitle());
            binding.includeMain.viewPager.setCurrentItem(index, false);
            return true;
        }
        return false;
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_privacy) {
            GuideTipsDialog.showTipsForce(this);
        } else if (id == R.id.action_about) {
            openNewPage(AboutFragment.class);
        }
        return false;
    }

    @SingleClick
    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.nav_header) {
            XToastUtils.toast("点击头部！");
        }
    }

    //================Navigation================//

    /**
     * 底部导航栏点击事件
     *
     * @param menuItem
     * @return
     */
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
        int index = CollectionUtils.arrayIndexOf(mTitles, menuItem.getTitle());
        if (index != -1) {
            binding.includeMain.toolbar.setTitle(menuItem.getTitle());
            binding.includeMain.viewPager.setCurrentItem(index, false);

            updateSideNavStatus(menuItem);
            return true;
        }
        return false;
    }

    /**
     * 更新侧边栏菜单选中状态
     *
     * @param menuItem
     */
    private void updateSideNavStatus(MenuItem menuItem) {
        MenuItem side = binding.navView.getMenu().findItem(menuItem.getItemId());
        if (side != null) {
            side.setChecked(true);
        }
    }

    /**
     * 菜单、返回键响应
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            ClickUtils.exitBy2Click(2000, this);
        }
        return true;
    }

    @Override
    public void onRetry() {
        XToastUtils.toast("再按一次退出程序");
    }

    @Override
    public void onExit() {
        XUtil.exitApp();
    }

    @Override
    protected void onResume() {
        super.onResume();
        int delay;
        delay = 1000000;


        //.....register sensors............
        if (Sensor_Acc != null) {
            mSensorManager.registerListener(this, Sensor_Acc, delay);
        }
        if (Sensor_Gyr != null) {
            mSensorManager.registerListener(this, Sensor_Gyr, delay);
        }
        if (Sensor_Mag != null) {
            mSensorManager.registerListener(this, Sensor_Mag, delay);
        }
        if (Sensor_Pre != null) {
            mSensorManager.registerListener(this, Sensor_Pre, delay);
        }
        if (Sensor_Ligh != null) {
            mSensorManager.registerListener(this, Sensor_Ligh, delay);
        }
        if (Sensor_Prox != null) {
            mSensorManager.registerListener(this, Sensor_Prox, delay);
        }
        if (Sensor_Humi != null) {
            mSensorManager.registerListener(this, Sensor_Humi, delay);
        }
        if (Sensor_Temp != null) {
            mSensorManager.registerListener(this, Sensor_Temp, delay);
        }
        if (Sensor_AHRS != null) {
            mSensorManager.registerListener(this, Sensor_AHRS, delay);
        }
        if (Sensor_LACC != null) {
            mSensorManager.registerListener(this, Sensor_LACC, delay);
        }
        if (Sensor_SGMO != null) {
            mSensorManager.registerListener(this, Sensor_SGMO, delay);
        }
        if (Sensor_STEP != null) {
            mSensorManager.registerListener(this, Sensor_STEP, delay);
        }
        if (Sensor_GAHRS != null) {
            mSensorManager.registerListener(this, Sensor_GAHRS, delay);
        }
        //TODO:增加处


    }


    @Override
    public void onSensorChanged(SensorEvent event) {
        if (tag) {
            long accuracy = event.accuracy;
            // TimeStamp del Sensor (a poner en el log_file)
            long SensorTimestamp_ns_raw = event.timestamp;      // in nano seconds
            double SensorTimestamp = ((double) (SensorTimestamp_ns_raw)) * 1E-9;  // de nano_s a segundos

            // Poner TimeStamp de la App (seg�n le llega el dato)
            long timestamp_ns_raw = System.nanoTime(); // in nano seconds
            if (timestamp_ns_raw >= tiempo_inicial_ns_raw)   // "tiempo_inicial_ns_raw" inicializado al dar al boton de grabar
            {
                timestamp_ns = timestamp_ns_raw - tiempo_inicial_ns_raw;
            } else {
                timestamp_ns = (timestamp_ns_raw - tiempo_inicial_ns_raw) + Long.MAX_VALUE;
            }
            timestamp = ((double) (timestamp_ns)) * 1E-9;  // de nano_s a segundos


            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

                contador_Acce++;
                //double resto=Math.IEEEremainder(contador_Acce, 10);
                if (SensorTimestamp - timestamp_Acce_last > 0) {
                    freq_medida_Acce = (float) (0.9 * freq_medida_Acce + 0.1 / (SensorTimestamp - timestamp_Acce_last));
                } else {
                    Log.e("ACCE SENSOR", "timestamp<timestamp_Acce_last");
                }
                timestamp_Acce_last = SensorTimestamp;

                // Many sensors return 3 values, one for each axis.
                float[] Acc_data = event.values;

                // Do something with this sensor value.
                if (timestamp - timestamp_Acce_last_update > deltaT_update) // cada 0.5 segundos actualizo la pantalla
                {
                    String cadena_display = String.format(Locale.US, "\tAcc(X): \t%10.5f \tm/s^2\n\tAcc(Y): \t%10.5f \tm/s^2\n\tAcc(Z): \t%10.5f \tm/s^2\n\t\t\t\t\t\t\t\tFreq: %5.0f Hz", Acc_data[0], Acc_data[1], Acc_data[2], freq_medida_Acce);
                    timestamp_Acce_last_update = timestamp;
                }

                {
                    try {
                        String cadena_file = String.format(Locale.US, "\nACCE;%.3f;%.3f;%.5f;%.5f;%.5f;%d;%d", timestamp, SensorTimestamp, Acc_data[0], Acc_data[1], Acc_data[2], accuracy, System.currentTimeMillis());
                        fout.write(cadena_file);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            } // end-if


            if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {

                contador_Gyro++;

                // Many sensors return 3 values, one for each axis.
                float[] Gyr_data = event.values;

                // Do something with this sensor value.
                if (SensorTimestamp - timestamp_Gyro_last > 0) {
                    freq_medida_Gyro = (float) (0.99 * freq_medida_Gyro + 0.01 / (SensorTimestamp - timestamp_Gyro_last));
                }
                timestamp_Gyro_last = SensorTimestamp;

                if (timestamp - timestamp_Gyro_last_update > deltaT_update) // cada 0.5 segundos actualizo la pantalla
                {
                    String cadena_display = String.format(Locale.US, "\tGyr(X): \t%10.5f \trad/s\n\tGyr(Y): \t%10.5f \trad/s\n\tGyr(Z): \t%10.5f \trad/s\n\t\t\t\t\t\t\t\tFreq: %5.0f Hz", Gyr_data[0], Gyr_data[1], Gyr_data[2], freq_medida_Gyro);
                    timestamp_Gyro_last_update = timestamp;
                }

                // Si grabando datos en log
                {
                    try {
                        String cadena_file = String.format(Locale.US, "\nGYRO;%.3f;%.3f;%.5f;%.5f;%.5f;%d;%d", timestamp, SensorTimestamp, Gyr_data[0], Gyr_data[1], Gyr_data[2], accuracy, System.currentTimeMillis());
                        fout.write(cadena_file);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            } // end-if

            if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {

                contador_Magn++;
                if (SensorTimestamp - timestamp_Magn_last > 0) {
                    freq_medida_Magn = (float) (0.9 * freq_medida_Magn + 0.1 / (SensorTimestamp - timestamp_Magn_last));
                }
                timestamp_Magn_last = SensorTimestamp;
                // Many sensors return 3 values, one for each axis.
                float[] Mag_data = event.values;
                // Do something with this sensor value.
                if (timestamp - timestamp_Magn_last_update > deltaT_update) // cada 0.5 segundos actualizo la pantalla
                {
                    String cadena_display = String.format(Locale.US, "\tMag(X): \t%10.5f \tuT\n\tMag(Y): \t%10.5f \tuT\n\tMag(Z): \t%10.5f \tuT\n\t\t\t\t\t\t\t\tFreq: %5.0f Hz", Mag_data[0], Mag_data[1], Mag_data[2], freq_medida_Magn);
                    timestamp_Magn_last_update = timestamp;
                }
                {
                    try {
                        String cadena_file = String.format(Locale.US, "\nMAGN;%.3f;%.3f;%.5f;%.5f;%.5f;%d;%d", timestamp, SensorTimestamp, Mag_data[0], Mag_data[1], Mag_data[2], accuracy, System.currentTimeMillis());
                        fout.write(cadena_file);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            } // end-if

            if (event.sensor.getType() == Sensor.TYPE_PRESSURE) {
                contador_Pres++;
                freq_medida_Pres = (float) (0.9 * freq_medida_Pres + 0.1 / (SensorTimestamp - timestamp_Pres_last));
                timestamp_Pres_last = SensorTimestamp;
                // Many sensors return 3 values, one for each axis.
                float[] Pre_data = event.values;
                // Do something with this sensor value.
                if (timestamp - timestamp_Pres_last_update > deltaT_update) // cada 0.5 segundos actualizo la pantalla
                {
                    String cadena_display = String.format(Locale.US, "\tPresssure: \t%8.2f \tmbar\n\t\t\t\t\t\t\t\tFreq: %5.0f Hz", Pre_data[0], freq_medida_Pres);
                    timestamp_Pres_last_update = timestamp;
                }
                {
                    try {
                        String cadena_file = String.format(Locale.US, "\nPRES;%.3f;%.3f;%.4f;%d", timestamp, SensorTimestamp, Pre_data[0], accuracy);
                        fout.write(cadena_file);
                    } catch (IOException e) {//
                        e.printStackTrace();
                    }
                }
            } // end-if

            if (event.sensor.getType() == Sensor.TYPE_LIGHT) {
                contador_Ligh++;
                freq_medida_Ligh = (float) (0.9 * freq_medida_Ligh + 0.1 / (SensorTimestamp - timestamp_Ligh_last));
                timestamp_Ligh_last = SensorTimestamp;
                // Many sensors return 3 values, one for each axis.
                float[] Ligh_data = event.values;
                // Do something with this sensor value.
                if (timestamp - timestamp_Ligh_last_update > deltaT_update) // cada 0.5 segundos actualizo la pantalla
                {
                    String cadena_display = String.format(Locale.US, "\tLight Intensity: \t%8.1f \tLux\n\t\t\t\t\t\t\t\tFreq: %5.0f Hz", Ligh_data[0], freq_medida_Ligh);
                    timestamp_Ligh_last_update = timestamp;
                }
                {
//				try {
////					String cadena_file=String.format(Locale.US,"\nLIGH;%.3f;%.3f;%.1f;%d",timestamp,SensorTimestamp,Ligh_data[0],accuracy);
////					fout.write(cadena_file);
//				} catch (IOException e) {
//					e.printStackTrace();
//				}
                }
            } // end-if

            if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) {
                contador_Prox++;
                freq_medida_Prox = (float) (0.9 * freq_medida_Prox + 0.1 / (SensorTimestamp - timestamp_Prox_last));
                timestamp_Prox_last = SensorTimestamp;
                // Many sensors return 3 values, one for each axis.
                float[] Prox_data = event.values;
                // Do something with this sensor value.
                if (timestamp - timestamp_Prox_last_update > deltaT_update) // cada 0.5 segundos actualizo la pantalla
                {
                    String cadena_display = String.format(Locale.US, "\tProximity: \t%8.1f \tUnits\n\t\t\t\t\t\t\t\tFreq: %5.0f Hz", Prox_data[0], freq_medida_Prox);
                    timestamp_Prox_last_update = timestamp;
                }
                {
//				try {
////					String cadena_file=String.format(Locale.US,"\nPROX;%.3f;%.3f;%.1f;%d",timestamp,SensorTimestamp,Prox_data[0],accuracy);
////					fout.write(cadena_file);
//				} catch (IOException e) {//
//					e.printStackTrace();
//				}
                }
            } // end-if

            if (event.sensor.getType() == Sensor.TYPE_RELATIVE_HUMIDITY) {
                contador_Humi++;
                freq_medida_Humi = (float) (0.9 * freq_medida_Humi + 0.1 / (SensorTimestamp - timestamp_Humi_last));
                timestamp_Humi_last = SensorTimestamp;
                // Many sensors return 3 values, one for each axis.
                float[] Humi_data = event.values;
                // Do something with this sensor value.
                if (timestamp - timestamp_Humi_last_update > deltaT_update) // cada 0.5 segundos actualizo la pantalla
                {
                    String cadena_display = String.format(Locale.US, "\tRelative Humidity: \t%8.1f \t%%\n\t\t\t\t\t\t\t\tFreq: %5.0f Hz", Humi_data[0], freq_medida_Humi);  // para poner "%" en string => poner %%
                    timestamp_Humi_last_update = timestamp;
                }
                {
                    try {
                        String cadena_file = String.format(Locale.US, "\nHUMI;%.3f;%.3f;%.1f;%d", timestamp, SensorTimestamp, Humi_data[0], accuracy);
                        fout.write(cadena_file);
                    } catch (IOException e) {//
                        e.printStackTrace();
                    }
                }
            } // end-if

            if (event.sensor.getType() == Sensor.TYPE_AMBIENT_TEMPERATURE) {
                contador_Temp++;
                freq_medida_Temp = (float) (0.9 * freq_medida_Temp + 0.1 / (SensorTimestamp - timestamp_Temp_last));
                timestamp_Temp_last = SensorTimestamp;
                // Many sensors return 3 values, one for each axis.
                float[] Temp_data = event.values;
                // Do something with this sensor value.
                if (timestamp - timestamp_Temp_last_update > deltaT_update) // cada 0.5 segundos actualizo la pantalla
                {
                    String cadena_display = String.format(Locale.US, "\tAmbient Temperature: \t%8.1f \t�C\n\t\t\t\t\t\t\t\tFreq: %5.0f Hz", Temp_data[0], freq_medida_Temp);
                    timestamp_Temp_last_update = timestamp;
                }
                {
                    try {
                        String cadena_file = String.format(Locale.US, "\nTEMP;%.3f;%.3f;%.1f;%d", timestamp, SensorTimestamp, Temp_data[0], accuracy);
                        fout.write(cadena_file);
                    } catch (IOException e) {//
                        e.printStackTrace();
                    }
                }
            } // end-if

            if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
                contador_Ahrs++;
                freq_medida_Ahrs = (float) (0.9 * freq_medida_Ahrs + 0.1 / (SensorTimestamp - timestamp_Ahrs_last));
                timestamp_Ahrs_last = SensorTimestamp;
                // Many sensors return 3 values, one for each axis.
                float[] AHRS_data = event.values;
			/*values[0]: x*sin(θ/2)
			values[1]: y*sin(θ/2)
			values[2]: z*sin(θ/2)
			values[3]: cos(θ/2)
			values[4]: estimated heading Accuracy (in radians) (-1 if unavailable)
			values[3], originally optional, will always be present from SDK Level 18 onwards. values[4] is a new value that has been added in SDK Level 18. */

                // Cambiar formato de "Rotation vector" a "Azimuth,Pitch,Roll"
                float[] Rot_b_g = {1, 0, 0, 0, 1, 0, 0, 0, 1};

                //............................
                // Aplico remedio para evitar el error:
                //     "java.lang.IllegalArgumentException: R array length must be 3 or 4"
                //     "at android.hardware.SensorManager.getRotationMatrixFromVector(SensorManager.java:1336)"
                // leido en: https://groups.google.com/forum/#!topic/android-developers/U3N9eL5BcJk

                // En vez de esto:
                //      SensorManager.getRotationMatrixFromVector(Rot_b_g, AHRS_data);  // Obtengo "Matriz rotacion" (en ENU)
                //pongo esto:
                try {
                    SensorManager.getRotationMatrixFromVector(Rot_b_g, AHRS_data);
                } catch (IllegalArgumentException e) {
                    if (AHRS_data.length > 3) {
                        // Note 3 bug
                        float[] newVector = new float[]{
                                AHRS_data[0],
                                AHRS_data[1],
                                AHRS_data[2]
                        };
                        SensorManager.getRotationMatrixFromVector(Rot_b_g, newVector);
                    }
                }
                //............................

                float[] orientacion = {0, 0, 0};  // AzimutZ[0], PitchX[1] and RollY[2]
                orientacion = SensorManager.getOrientation(Rot_b_g, orientacion);  // En radianes pero lo da en WND (West/North/Down)
                orientacion[0] = -orientacion[0];
                orientacion[1] = -orientacion[1]; // Paso de WND a de nuevo ENU (que es donde quiero trabajar)
                double PI = 3.14159265358979323846;
                float yaw_Z = (float) (orientacion[0] * 180 / PI);  // Yaw, ejeZ en grados
                float pitch_X = (float) (orientacion[1] * 180 / PI);  // Pitch, eje X
                float roll_Y = (float) (orientacion[2] * 180 / PI);  // Roll, eje Y

                //DecimalFormat
                if (timestamp - timestamp_Ahrs_last_update > deltaT_update) // cada 0.5 segundos actualizo la pantalla
                {
                    String cadena_display = String.format(Locale.US, "\tPitch(X): \t%10.3f \t\tdegrees\n\tRoll(Y): \t%10.3f \t\tdegrees\n\tYaw(Z): \t%10.3f \tdegrees\n\t\t\t\t\t\t\t\tFreq: %5.0f Hz", pitch_X, roll_Y, yaw_Z, freq_medida_Ahrs);
                    timestamp_Ahrs_last_update = timestamp;
                }

                // Do something with this sensor value.

                {
                    try {
                        //String cadena_file=String.format(Locale.US,"\nAHRS;%.3f;%.3f;%.4f;%.4f;%.4f;%.6f;%.6f;%.6f;%.6f;%d;%.9f;%.9f;%.9f;%.9f;%.9f;%.9f;%.9f;%.9f;%.9f",
                        //		timestamp,SensorTimestamp,pitch_X,roll_Y,yaw_Z,AHRS_data[0],AHRS_data[1],AHRS_data[2],AHRS_data[3],accuracy,Rot_b_g[0],Rot_b_g[1],Rot_b_g[2],Rot_b_g[3],Rot_b_g[4],Rot_b_g[5],Rot_b_g[6],Rot_b_g[7],Rot_b_g[8]);

                        String cadena_file = String.format(Locale.US, "\nAHRS;%.3f;%.3f;%.6f;%.6f;%.6f;%.8f;%.8f;%.8f;%d;%d",
                                timestamp, SensorTimestamp, pitch_X, roll_Y, yaw_Z, AHRS_data[0], AHRS_data[1], AHRS_data[2], accuracy, System.currentTimeMillis());
                        fout.write((cadena_file));
                    } catch (IOException e) {//
                        e.printStackTrace();
                    }
                }
            } // end-if

            if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
                contador_Lacc++;
                // Many sensors return 3 values, one for each axis.
                float[] Lacc_data = event.values;


                {
                    try {
                        String cadena_file = String.format(Locale.US, "\nLACC;%.3f;%.3f;%.5f;%.5f;%.5f;%d;%d", timestamp, SensorTimestamp, Lacc_data[0], Lacc_data[1], Lacc_data[2], accuracy, System.currentTimeMillis());
                        fout.write(cadena_file);
                    } catch (IOException e) {//
                        e.printStackTrace();
                    }
                }
            }
            if (event.sensor.getType() == Sensor.TYPE_SIGNIFICANT_MOTION) {
                contador_Sgmo++;
                // Many sensors return 3 values, one for each axis.
                float[] SGMO_data = event.values;
                {
                    try {
                        String cadena_file = String.format(Locale.US, "\nSGMO;%.3f;%.3f;%f;%d;%d", timestamp, SensorTimestamp, SGMO_data[0], accuracy, System.currentTimeMillis());
                        fout.write(cadena_file);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            if (event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) {
                contador_Step++;
                // Many sensors return 3 values, one for each axis.
                float[] STEP_data = event.values;
                {
                    try {
                        String cadena_file = String.format(Locale.US, "\nSTEP;%.3f;%.3f;%f;%d;%d", timestamp, SensorTimestamp, STEP_data[0], accuracy, System.currentTimeMillis());
                        fout.write(cadena_file);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            if (event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) {
                contador_Gahrs++;
                // Many sensors return 3 values, one for each axis.
                float[] Gahrs_data = event.values;
                {
                    try {
                        String cadena_file = String.format(Locale.US, "\nSTEP;%.3f;%.3f;%f;%f;%f;%f;%f;%d;%d", timestamp, SensorTimestamp, Gahrs_data[0], Gahrs_data[1], Gahrs_data[2], Gahrs_data[3], Gahrs_data[4], accuracy, System.currentTimeMillis());
                        fout.write(cadena_file);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {

    }


}

